#ifndef __RING_QUEUE_HPP__
#define __RING_QUEUE_HPP__

#include <iostream>
#include <vector>
#include "LockGuard.hpp"
#include "Sem.hpp"
#include "Log.hpp"

const int g_num=5;

//上层看到ring_queue这一个场所，而这个场所中的push和pop动作的原子性是需要这个场所本身维护，我上层并不关心
template<class T>
class RingQueue
{
public:
    RingQueue(int num=g_num)
        :_ring_queue(num)
        ,_num(num)
        ,c_step(0)
        ,p_step(0)
        ,_space_sem(num)
        ,_data_sem(0)
    {
        pthread_mutex_init(&_c_mtx,nullptr);
        pthread_mutex_init(&_p_mtx,nullptr);
    }

    void push(const T& in)
    {
        _space_sem.p();//所有的生产者都要来预定空间资源，当空间资源不够的时候就会被挂起
        LockGuard lg(&_p_mtx);
        _ring_queue[p_step++]=in;
        p_step%=_num;
        _data_sem.v();
    }

    void pop(T* out)
    {
        _data_sem.p();//所有的消费者都要来预定数据资源，当数据资源不够的时候就会被挂起
        LockGuard lg(&_c_mtx);
        *out=_ring_queue[c_step++];
        c_step%=_num;
        _space_sem.v();
    }

    ~RingQueue()
    {
        pthread_mutex_destroy(&_c_mtx);
        pthread_mutex_destroy(&_p_mtx);
    }

private:
    std::vector<T> _ring_queue;//环形队列
    int _num;//记录环形队列大小
    int c_step;//消费者下标
    int p_step;//生产者下标
    pthread_mutex_t _c_mtx;//消费锁
    pthread_mutex_t _p_mtx;//生产锁
    Sem _space_sem;//空间信号量
    Sem _data_sem;//资源信号量
};



#endif